import type {
  RequestMethods,
  SimpleHttpRequestConfig,
  SimpleHttpResponse,
} from './type'
import { close, start } from '@/utils/nprogress'
import Axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type CustomParamsSerializer,
} from 'axios'
import { stringify } from 'qs'

const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 60000,
  headers: {
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json',
    'X-Requested-With': 'XMLHttpRequest',
  },
  // baseURL: import.meta.env.VITE_BASE_URL as string,
  baseURL: '/api',
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer,
  },
}

// 白名单，忽略token
const whiteList: string[] = [
  '/auth/oauth2/token',
  '/admin-api/system/file/upload/public',
  '/admin-api/system/oauth2/code/login',
  '/admin-api/system/oauth2ThirdClient/oauth2ThirdClientList',
]

/**
 * 封装Http请求类
 */
class SimpleHttp {
  /** token过期后，暂存待执行的请求 */
  private static requests: Array<() => Promise<ResultData<any>>> = []
  /** 防止重复刷新token */
  private static isRefreshing = false
  /** 初始化配置对象 */
  private static initConfig: SimpleHttpRequestConfig = {}
  /** 保存当前Axios实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig)

  constructor() {
    this.httpInterceptorsRequest()
    this.httpInterceptorsResponse()
  }

  /**
   * 通用请求函数
   * @param method 请求方法
   * @param url 请求地址
   * @param param 请求参数
   * @param axiosConfig 其它配置
   */
  public async request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: SimpleHttpRequestConfig,
  ): Promise<ResultData<T>> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig,
    } as SimpleHttpRequestConfig
    // 单独处理自定义请求/响应回调
    return new Promise<ResultData<T>>((resolve, reject) => {
      SimpleHttp.axiosInstance.request(config).then((response: any) => {
        if (response == null) {
          reject(new Error('请求失败'))
          close()
          return
        }
        if (response.code >= 200 && response.code <= 300) {
          resolve(response as ResultData<T>)
        }
        else if (response.code === 401) {
          useUserStoreHook().logout(true)
          // 状态码401 刷新token
          // SimpleHttp.requests.push(() => {
          //   return this.request<T>(method, url, param, axiosConfig)
          // })
          // this.RefreshToken()
        }
        else if (!response.success) {
          Message({
            type: 'error',
            message: response.msg,
          })
          reject(response.msg)
        }
        else {
          reject(response.msg)
        }
      })
    })
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    SimpleHttp.axiosInstance.interceptors.request.use(
      async (config: any): Promise<any> => {
        // 打开进度条
        start()
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === 'function') {
          config.beforeRequestCallback(config)
          return config
        }
        if (SimpleHttp.initConfig.beforeRequestCallback) {
          SimpleHttp.initConfig.beforeRequestCallback(config)
          return config
        }
        if (whiteList.find(url => url === config.url))
          return config
        // 设置token
        config.headers.Authorization = useUserStoreHook().getAccessToken()
        // 设置租户Id
        config.headers['x-tenant-id'] = useUserStoreHook().getTenantId()
        return config
      },
      async (error) => {
        return Promise.reject(error)
      },
    )
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    SimpleHttp.axiosInstance.interceptors.response.use(
      (response: SimpleHttpResponse) => {
        // 关闭进度条
        close()
        return response.data
      },
    )
  }

  /**
   * 刷新token
   * @constructor
   * @private
   */
  private RefreshToken() {
    // TODO刷新Token
  }
}

export const http = new SimpleHttp()
